package net.qiqbframework.messaging.task;

import net.qiqbframework.messaging.MetaData;

import java.util.Deque;
import java.util.LinkedList;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;


public abstract class CurrentMessageTask {

    private static final ThreadLocal<Deque<MessageTask<?>>> CURRENT = new ThreadLocal<>();

    public static boolean isStarted() {
        return CURRENT.get() != null && !CURRENT.get().isEmpty();
    }

    public static boolean ifStarted(Consumer<MessageTask<?>> consumer) {
        if (isStarted()) {
            consumer.accept(get());
            return true;
        }
        return false;
    }

    public static <T> Optional<T> map(Function<MessageTask<?>, T> function) {
        return isStarted() ? Optional.ofNullable(function.apply(get())) : Optional.empty();
    }

    public static MessageTask<?> get() {
        if (isEmpty()) {
            throw new IllegalStateException("No MessageWork is currently started for this thread.");
        }
        return CURRENT.get().peek();
    }

    private static boolean isEmpty() {
        Deque<MessageTask<?>> unitsOfWork = CURRENT.get();
        return unitsOfWork == null || unitsOfWork.isEmpty();
    }


    public static void commit() {
        get().commit();
    }

    public static void set(MessageTask<?> MessageWork) {
        if (CURRENT.get() == null) {
            CURRENT.set(new LinkedList<>());
        }
        CURRENT.get().push(MessageWork);
    }


    public static void clear(MessageTask<?> MessageWork) {
        if (!isStarted()) {
            throw new IllegalStateException("Could not clear this MessageWork. There is no MessageWork active.");
        }
        if (CURRENT.get().peek() == MessageWork) {
            CURRENT.get().pop();
            if (CURRENT.get().isEmpty()) {
                CURRENT.remove();
            }
        } else {
            throw new IllegalStateException("Could not clear this MessageWork. It is not the active one.");
        }
    }


    public static MetaData correlationData() {
        return CurrentMessageTask.map(MessageTask::getCorrelationData).orElse(MetaData.emptyInstance());
    }

    private CurrentMessageTask() {
    }
}
